summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
blob: 4cfdf45588f65e64cb6411dfc01aec01aca79a2d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <random>

#include "common/literals.h"
#include "common/settings.h"

#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
#include "core/hle/kernel/k_trace.h"

namespace Kernel::Board::Nintendo::Nx {

namespace impl {

using namespace Common::Literals;

constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2280 * 4_KiB;
constexpr const std::size_t RequiredNonSecureSystemMemorySizeViFatal = 0x200 * 4_KiB;
constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x704 * 4_KiB;
constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4_KiB;

} // namespace impl

constexpr const std::size_t RequiredNonSecureSystemMemorySize =
    impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
    impl::RequiredNonSecureSystemMemorySizeMisc;

constexpr const std::size_t RequiredNonSecureSystemMemorySizeWithFatal =
    RequiredNonSecureSystemMemorySize + impl::RequiredNonSecureSystemMemorySizeViFatal;

namespace {

using namespace Common::Literals;

u32 GetMemorySizeForInit() {
    switch (Settings::values.memory_layout_mode.GetValue()) {
    case Settings::MemoryLayout::Memory_4Gb:
        return Smc::MemorySize_4GB;
    case Settings::MemoryLayout::Memory_6Gb:
        return Smc::MemorySize_6GB;
    case Settings::MemoryLayout::Memory_8Gb:
        return Smc::MemorySize_8GB;
    }
    return Smc::MemorySize_4GB;
}

Smc::MemoryArrangement GetMemoryArrangeForInit() {
    switch (Settings::values.memory_layout_mode.GetValue()) {
    case Settings::MemoryLayout::Memory_4Gb:
        return Smc::MemoryArrangement_4GB;
    case Settings::MemoryLayout::Memory_6Gb:
        return Smc::MemoryArrangement_6GB;
    case Settings::MemoryLayout::Memory_8Gb:
        return Smc::MemoryArrangement_8GB;
    }
    return Smc::MemoryArrangement_4GB;
}
} // namespace

size_t KSystemControl::Init::GetRealMemorySize() {
    return GetIntendedMemorySize();
}

// Initialization.
size_t KSystemControl::Init::GetIntendedMemorySize() {
    switch (GetMemorySizeForInit()) {
    case Smc::MemorySize_4GB:
    default: // All invalid modes should go to 4GB.
        return 4_GiB;
    case Smc::MemorySize_6GB:
        return 6_GiB;
    case Smc::MemorySize_8GB:
        return 8_GiB;
    }
}

KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(KPhysicalAddress base_address) {
    const size_t real_dram_size = KSystemControl::Init::GetRealMemorySize();
    const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize();
    if (intended_dram_size * 2 < real_dram_size) {
        return base_address;
    } else {
        return base_address + ((real_dram_size - intended_dram_size) / 2);
    }
}

bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
    return true;
}

std::size_t KSystemControl::Init::GetApplicationPoolSize() {
    // Get the base pool size.
    const size_t base_pool_size = []() -> size_t {
        switch (GetMemoryArrangeForInit()) {
        case Smc::MemoryArrangement_4GB:
        default:
            return 3285_MiB;
        case Smc::MemoryArrangement_4GBForAppletDev:
            return 2048_MiB;
        case Smc::MemoryArrangement_4GBForSystemDev:
            return 3285_MiB;
        case Smc::MemoryArrangement_6GB:
            return 4916_MiB;
        case Smc::MemoryArrangement_6GBForAppletDev:
            return 3285_MiB;
        case Smc::MemoryArrangement_8GB:
            // Real kernel sets this to 4916_MiB. We are not debugging applets.
            return 6547_MiB;
        }
    }();

    // Return (possibly) adjusted size.
    return base_pool_size;
}

size_t KSystemControl::Init::GetAppletPoolSize() {
    // Get the base pool size.
    const size_t base_pool_size = []() -> size_t {
        switch (GetMemoryArrangeForInit()) {
        case Smc::MemoryArrangement_4GB:
        default:
            return 507_MiB;
        case Smc::MemoryArrangement_4GBForAppletDev:
            return 1554_MiB;
        case Smc::MemoryArrangement_4GBForSystemDev:
            return 448_MiB;
        case Smc::MemoryArrangement_6GB:
            return 562_MiB;
        case Smc::MemoryArrangement_6GBForAppletDev:
            return 2193_MiB;
        case Smc::MemoryArrangement_8GB:
            //! Real kernel sets this to 2193_MiB. We are not debugging applets.
            return 562_MiB;
        }
    }();

    // Return (possibly) adjusted size.
    constexpr size_t ExtraSystemMemoryForAtmosphere = 33_MiB;
    return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}

size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
    // Verify that our minimum is at least as large as Nintendo's.
    constexpr size_t MinimumSizeWithFatal = RequiredNonSecureSystemMemorySizeWithFatal;
    static_assert(MinimumSizeWithFatal >= 0x2C04000);

    constexpr size_t MinimumSizeWithoutFatal = RequiredNonSecureSystemMemorySize;
    static_assert(MinimumSizeWithoutFatal >= 0x2A00000);

    return MinimumSizeWithFatal;
}

namespace {
template <typename F>
u64 GenerateUniformRange(u64 min, u64 max, F f) {
    // Handle the case where the difference is too large to represent.
    if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
        return f();
    }

    // Iterate until we get a value in range.
    const u64 range_size = ((max + 1) - min);
    const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
    while (true) {
        if (const u64 rnd = f(); rnd < effective_max) {
            return min + (rnd % range_size);
        }
    }
}

} // Anonymous namespace

u64 KSystemControl::GenerateRandomU64() {
    std::random_device device;
    std::mt19937 gen(device());
    std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
    return distribution(gen);
}

u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
    return GenerateUniformRange(min, max, GenerateRandomU64);
}

} // namespace Kernel::Board::Nintendo::Nx